home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / vpropagate.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-15  |  31.2 KB  |  1,106 lines

  1. /* vpropagate.c -- This is a plug-in for the GIMP (1.0's API)
  2.  * Author: Shuji Narazaki <narazaki@InetQ.or.jp>
  3.  * Time-stamp: <2000-01-09 15:50:46 yasuhiro>
  4.  * Version: 0.89a
  5.  *
  6.  * Copyright (C) 1996-1997 Shuji Narazaki <narazaki@InetQ.or.jp>
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. /* memo
  24.    the initial value of each pixel is the value of the pixel itself.
  25.    To determine whether it is an isolated local peak point, use:
  26.    (self == min && (! modified_flag))   ; modified_flag holds history of update
  27.    In other word, pixel itself is not a neighbor of it.
  28. */
  29.  
  30. #include "config.h"
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35.  
  36. #include <gtk/gtk.h>
  37.  
  38. #include <libgimp/gimp.h>
  39. #include <libgimp/gimpui.h>
  40.  
  41. #include "libgimp/stdplugins-intl.h"
  42.  
  43.  
  44. #define    PLUG_IN_NAME    "plug_in_vpropagate"
  45. #define SHORT_NAME    "vpropagate"
  46.  
  47. typedef guchar CH;
  48. #define    VP_RGB            (1 << 0)
  49. #define VP_GRAY            (1 << 1)
  50. #define VP_WITH_ALPHA    (1 << 2)
  51. #define VP_WO_ALPHA    (1 << 3)
  52. #define num_direction    4
  53. #define Right2Left    0
  54. #define Bottom2Top    1
  55. #define    Left2Right    2
  56. #define Top2Bottom    3
  57.  
  58. static void        query                   (void);
  59. static void        run                        (gchar         *name,
  60.                             gint           nparams,
  61.                             GimpParam        *param,   
  62.                                                 gint          *nreturn_vals,
  63.                             GimpParam      **return_vals);
  64.  
  65. static GimpPDBStatusType  value_propagate            (gint           drawable_id);
  66. static void         value_propagate_body       (gint           drawable_id);
  67. static int        vpropagate_dialog          (GimpImageBaseType     image_type);
  68. static void        prepare_row                (GimpPixelRgn     *pixel_rgn,
  69.                         guchar        *data,
  70.                         int            x,
  71.                         int            y,
  72.                         int            w);
  73.  
  74. static void         vpropagate_ok_callback     (GtkWidget     *widget,
  75.                         gpointer       data);
  76. static GtkWidget *  gtk_table_add_toggle       (GtkWidget     *table,
  77.                         gchar          *name,
  78.                         gint           x1,
  79.                         gint           x2,
  80.                         gint           y,
  81.                         GtkSignalFunc  update,
  82.                         gint          *value);
  83.  
  84. static int        value_difference_check  (CH *, CH *, int);
  85. static void         set_value               (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  86. static void        initialize_white        (GimpImageBaseType, int, CH *, CH *, void **);
  87. static void        propagate_white         (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  88. static void        initialize_black        (GimpImageBaseType, int, CH *, CH *, void **);
  89. static void         propagate_black         (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  90. static void        initialize_middle       (GimpImageBaseType, int, CH *, CH *, void **);
  91. static void        propagate_middle        (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  92. static void        set_middle_to_peak      (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  93. static void        set_foreground_to_peak  (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  94. static void        initialize_foreground   (GimpImageBaseType, int, CH *, CH *, void **);
  95. static void        initialize_background   (GimpImageBaseType, int, CH *, CH *, void **);
  96. static void        propagate_a_color       (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  97. static void        propagate_opaque        (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  98. static void        propagate_transparent   (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  99.  
  100. GimpPlugInInfo PLUG_IN_INFO =
  101. {
  102.   NULL,  /* init_proc  */
  103.   NULL,  /* quit_proc  */
  104.   query, /* query_proc */
  105.   run,   /* run_proc   */
  106. };
  107.  
  108. #define UPDATE_STEP        20
  109. #define SCALE_WIDTH       100
  110. #define PROPAGATING_VALUE  1<<0
  111. #define PROPAGATING_ALPHA  1<<1
  112.  
  113. /* parameters */
  114. typedef struct
  115. {
  116.   gint        propagate_mode;
  117.   gint        propagating_channel;
  118.   gdouble    propagating_rate;
  119.   gint        direction_mask;
  120.   gint        lower_limit;
  121.   gint        upper_limit;
  122.   /* gint    channel_mask[3]; */
  123.   /* gint    peak_includes_equals; */
  124.   /* gint    overwrite; */
  125. } VPValueType;
  126.  
  127. static VPValueType vpvals = 
  128. {
  129.   0,
  130.   3,                /* PROPAGATING_VALUE + PROPAGATING_ALPHA */
  131.   1.0,                /* [0.0:1.0] */
  132.   15,                /* propagate to all 4 directions */
  133.   0,
  134.   255
  135. };
  136.  
  137. /* dialog vairables */
  138. static gint    propagate_alpha;
  139. static gint    propagate_value;
  140. static gint    direction_mask_vec[4];
  141. static gint    channel_mask[] = { 1, 1, 1 };
  142. static gint    peak_max = 1;
  143. static gint    peak_min = 1;
  144. static gint    peak_includes_equals = 1;
  145. static guchar    fore[3];
  146.  
  147. typedef struct
  148. {
  149.   gint    applicable_image_type;
  150.   gchar  *name;
  151.   void  (*initializer) ();
  152.   void  (*updater) ();
  153.   void  (*finalizer) ();
  154. } ModeParam;
  155.  
  156. #define num_mode 8
  157. static ModeParam modes[num_mode] = 
  158. {
  159.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
  160.     N_("More White (Larger Value)"),
  161.     initialize_white,      propagate_white,       set_value },
  162.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
  163.     N_("More Black (Smaller Value)"),
  164.     initialize_black,      propagate_black,       set_value },
  165.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
  166.     N_("Middle Value to Peaks"),
  167.     initialize_middle,     propagate_middle,      set_middle_to_peak },
  168.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
  169.     N_("Foreground to Peaks"),
  170.     initialize_middle,     propagate_middle,      set_foreground_to_peak },
  171.   { VP_RGB | VP_WITH_ALPHA | VP_WO_ALPHA,
  172.     N_("Only Foreground"),
  173.     initialize_foreground, propagate_a_color,     set_value },
  174.   { VP_RGB | VP_WITH_ALPHA | VP_WO_ALPHA,
  175.     N_("Only Background"),
  176.     initialize_background, propagate_a_color,     set_value },
  177.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA,
  178.     N_("More Opaque"),
  179.     NULL,                  propagate_opaque,      set_value },
  180.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA,
  181.     N_("More Transparent"),
  182.     NULL,                  propagate_transparent, set_value },
  183. };
  184.  
  185. typedef struct 
  186. {
  187.   gint run;
  188. } VPInterface;
  189.  
  190. static VPInterface vpropagate_interface = { FALSE };
  191. static gint       drawable_id;
  192.  
  193. MAIN ()
  194.  
  195. static void
  196. query (void)
  197. {
  198.   static GimpParamDef args[] =
  199.   {
  200.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  201.     { GIMP_PDB_IMAGE, "image", "Input image (not used)" },
  202.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  203.     { GIMP_PDB_INT32, "propagate-mode", "propagate 0:white, 1:black, 2:middle value 3:foreground to peak, 4:foreground, 5:background, 6:opaque, 7:transparent" },
  204.     { GIMP_PDB_INT32, "propagating-channel", "channels which values are propagated" },
  205.     { GIMP_PDB_FLOAT, "propagating-rate", "0.0 <= propagatating_rate <= 1.0" },
  206.     { GIMP_PDB_INT32, "direction-mask", "0 <= direction-mask <= 15" },
  207.     { GIMP_PDB_INT32, "lower-limit", "0 <= lower-limit <= 255" },
  208.     { GIMP_PDB_INT32, "upper-limit", "0 <= upper-limit <= 255" }
  209.   };
  210.   static gint nargs = sizeof (args) / sizeof (args[0]);
  211.  
  212.   gimp_install_procedure (PLUG_IN_NAME,
  213.               "Propagate values of the layer",
  214.               "Propagate values of the layer",
  215.               "Shuji Narazaki (narazaki@InetQ.or.jp)",
  216.               "Shuji Narazaki",
  217.               "1996-1997",
  218.               N_("<Image>/Filters/Distorts/Value Propagate..."),
  219.               "RGB*,GRAY*",
  220.               GIMP_PLUGIN,
  221.               nargs, 0,
  222.               args, NULL);
  223. }
  224.  
  225. static void
  226. run (gchar   *name,
  227.      gint     nparams,
  228.      GimpParam  *param,
  229.      gint    *nreturn_vals,
  230.      GimpParam **return_vals)
  231. {
  232.   static GimpParam     values[1];
  233.   GimpPDBStatusType    status = GIMP_PDB_SUCCESS;
  234.   GimpRunModeType    run_mode;
  235.   
  236.   run_mode = param[0].data.d_int32;
  237.   drawable_id = param[2].data.d_int32;
  238.  
  239.   *nreturn_vals = 1;
  240.   *return_vals = values;
  241.   
  242.   values[0].type = GIMP_PDB_STATUS;
  243.   values[0].data.d_status = status;
  244.  
  245.   switch (run_mode)
  246.     {
  247.     case GIMP_RUN_INTERACTIVE:
  248.       INIT_I18N_UI();
  249.       gimp_get_data (PLUG_IN_NAME, &vpvals);
  250.       /* building the values of dialog variables from vpvals. */
  251.       propagate_alpha =
  252.     (vpvals.propagating_channel & PROPAGATING_ALPHA) ? TRUE : FALSE;
  253.       propagate_value =
  254.     (vpvals.propagating_channel & PROPAGATING_VALUE) ? TRUE : FALSE;
  255.       {
  256.     int    i;
  257.     for (i = 0; i < 4; i++)
  258.       direction_mask_vec[i] = (vpvals.direction_mask & (1 << i))
  259.         ? TRUE : FALSE;
  260.       }
  261.       if (! vpropagate_dialog (gimp_drawable_type(drawable_id)))
  262.     return;
  263.       break;
  264.     case GIMP_RUN_NONINTERACTIVE:
  265.       INIT_I18N();
  266.       vpvals.propagate_mode = param[3].data.d_int32;
  267.       vpvals.propagating_channel = param[4].data.d_int32;
  268.       vpvals.propagating_rate = param[5].data.d_float;
  269.       vpvals.direction_mask = param[6].data.d_int32;
  270.       vpvals.lower_limit = param[7].data.d_int32;
  271.       vpvals.upper_limit = param[8].data.d_int32;
  272.       break;
  273.     case GIMP_RUN_WITH_LAST_VALS:
  274.       INIT_I18N();
  275.       gimp_get_data (PLUG_IN_NAME, &vpvals);
  276.       break;
  277.     }
  278.   
  279.   status = value_propagate (drawable_id);
  280.  
  281.   if (run_mode != GIMP_RUN_NONINTERACTIVE)
  282.     gimp_displays_flush();
  283.   if (run_mode == GIMP_RUN_INTERACTIVE && status == GIMP_PDB_SUCCESS)
  284.     gimp_set_data (PLUG_IN_NAME, &vpvals, sizeof (VPValueType));
  285.  
  286.   values[0].type = GIMP_PDB_STATUS;
  287.   values[0].data.d_status = status;
  288. }
  289.  
  290. /* registered function entry */
  291. static GimpPDBStatusType
  292. value_propagate (gint drawable_id)
  293. {
  294.   /* check the validness of parameters */
  295.   if (!(vpvals.propagating_channel & (PROPAGATING_VALUE | PROPAGATING_ALPHA)))
  296.     {
  297.       /* gimp_message ("No channel selected."); */
  298.       return GIMP_PDB_EXECUTION_ERROR;
  299.     }
  300.   if (vpvals.direction_mask == 0)
  301.     {
  302.       /* gimp_message ("No direction selected."); */
  303.       return GIMP_PDB_EXECUTION_ERROR;
  304.     }
  305.   if ((vpvals.lower_limit < 0) || (255 < vpvals.lower_limit) ||
  306.        (vpvals.upper_limit < 0) || (255 < vpvals.lower_limit) ||
  307.        (vpvals.upper_limit < vpvals.lower_limit))
  308.     {
  309.       /* gimp_message ("Limit values are not valid."); */
  310.       return GIMP_PDB_EXECUTION_ERROR;
  311.     }
  312.   value_propagate_body (drawable_id);
  313.   return GIMP_PDB_SUCCESS;
  314. }
  315.  
  316. static void
  317. value_propagate_body (gint drawable_id)
  318. {
  319.   GimpDrawable  *drawable;
  320.   GimpImageBaseType  dtype;
  321.   ModeParam   operation;
  322.   GimpPixelRgn   srcRgn, destRgn;
  323.   guchar     *here, *best, *dest;
  324.   guchar     *dest_row, *prev_row, *cur_row, *next_row, *pr, *cr, *nr, *swap;
  325.   gint        width, height, bytes, index;
  326.   gint        begx, begy, endx, endy, x, y, dx;
  327.   gint        left_index, right_index, up_index, down_index;
  328.   void       *tmp;
  329.  
  330.   /* calculate neighbors' indexes */
  331.   left_index    = (vpvals.direction_mask & (1 << Left2Right)) ? -1 : 0;
  332.   right_index    = (vpvals.direction_mask & (1 << Right2Left)) ?  1 : 0;
  333.   up_index    = (vpvals.direction_mask & (1 << Top2Bottom)) ? -1 : 0;
  334.   down_index    = (vpvals.direction_mask & (1 << Bottom2Top)) ?  1 : 0;
  335.   operation = modes[vpvals.propagate_mode];
  336.   tmp = NULL;
  337.  
  338.   drawable = gimp_drawable_get (drawable_id);
  339.   dtype = gimp_drawable_type (drawable_id);
  340.  
  341.   /* Here I use the algorithm of blur.c . */
  342.   gimp_drawable_mask_bounds (drawable->id, &begx, &begy, &endx, &endy);
  343.  
  344.   width = drawable->width;
  345.   height = drawable->height;
  346.   bytes = drawable->bpp;
  347.  
  348.   gimp_tile_cache_ntiles (2 * ((endx - begx) / gimp_tile_width() + 1));
  349.  
  350.   prev_row = g_new (guchar, (endx - begx + 2) * bytes);
  351.   cur_row  = g_new (guchar, (endx - begx + 2) * bytes);
  352.   next_row = g_new (guchar, (endx - begx + 2) * bytes);
  353.   dest_row = g_new (guchar, (endx - begx) * bytes);
  354.  
  355.   gimp_pixel_rgn_init (&srcRgn, drawable, 0, 0, width, height, FALSE, FALSE);
  356.   gimp_pixel_rgn_init (&destRgn, drawable, 0, 0, width, height, TRUE, TRUE);
  357.  
  358.   pr = prev_row + bytes;
  359.   cr = cur_row + bytes;
  360.   nr = next_row + bytes;
  361.  
  362.   prepare_row (&srcRgn, pr, begx, (0 < begy) ? begy : begy - 1, endx-begx);
  363.   prepare_row (&srcRgn, cr, begx, begy, endx-begx);
  364.  
  365.   best = g_new (guchar, bytes);
  366.  
  367.   gimp_progress_init (_("Value propagating..."));
  368.   gimp_palette_get_foreground (fore+0, fore+1, fore+2);
  369.  
  370.   /* start real job */
  371.   for (y = begy ; y < endy ; y++) 
  372.     {
  373.       prepare_row (&srcRgn, nr, begx, ((y+1) < endy) ? y+1 : endy, endx-begx);
  374.       for (index = 0; index < (endx - begx) * bytes; index++)
  375.     dest_row[index] = cr[index];
  376.       for (x = 0 ; x < endx - begx; x++) 
  377.     {
  378.       dest = dest_row + (x * bytes);
  379.       here = cr + (x * bytes);
  380.       /* *** copy source value to best value holder *** */
  381.       memcpy ((void *)best, (void *)here, bytes);
  382.       if (operation.initializer)
  383.         (* operation.initializer)(dtype, bytes, best, here, &tmp);
  384.       /* *** gather neighbors' values: loop-unfolded version *** */
  385.       if (up_index == -1)
  386.         for (dx = left_index ; dx <= right_index ; dx++)
  387.           (* operation.updater)(dtype, bytes, here, pr+((x+dx)*bytes), best, tmp);
  388.       for (dx = left_index ; dx <= right_index ; dx++)
  389.         if (dx != 0)
  390.           (* operation.updater)(dtype, bytes, here, cr+((x+dx)*bytes), best, tmp);
  391.       if (down_index == 1)
  392.         for (dx = left_index ; dx <= right_index ; dx++)
  393.           (* operation.updater)(dtype, bytes, here, nr+((x+dx)*bytes), best, tmp);
  394.       /* *** store it to dest_row*** */
  395.       (* operation.finalizer)(dtype, bytes, best, here, dest, tmp);
  396.     }
  397.       /* now store destline to destRgn */
  398.       gimp_pixel_rgn_set_row (&destRgn, dest_row, begx, y, endx - begx);
  399.       /* shift the row pointers  */
  400.       swap = pr;
  401.       pr = cr;
  402.       cr = nr;
  403.       nr = swap;
  404.       /* update each UPDATE_STEP (optimizer must generate cheap code) */ 
  405.       if ((y % 5) == 0) /*(y % (int) ((endy - begy) / UPDATE_STEP)) == 0 */
  406.     gimp_progress_update ((double)y / (double)(endy - begy));
  407.     }
  408.   /*  update the region  */
  409.   gimp_progress_update(1.0);
  410.   gimp_drawable_flush (drawable);
  411.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  412.   gimp_drawable_update (drawable->id, begx, begy, endx-begx, endy-begy);
  413. }
  414.  
  415. static void
  416. prepare_row (GimpPixelRgn *pixel_rgn,
  417.          guchar    *data,
  418.          gint       x,
  419.          gint       y,
  420.          gint       w)
  421. {
  422.   gint b;
  423.  
  424.   if (y == 0)
  425.     gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y + 1), w);
  426.   else if (y == pixel_rgn->h)
  427.     gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y - 1), w);
  428.   else
  429.     gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w);
  430.  
  431.   /*  Fill in edge pixels  */
  432.   for (b = 0; b < pixel_rgn->bpp; b++)
  433.     {
  434.       data[-(gint)pixel_rgn->bpp + b] = data[b];
  435.       data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
  436.     }
  437. }
  438.  
  439. static void
  440. set_value (GimpImageBaseType  dtype, 
  441.        gint        bytes, 
  442.        guchar     *best, 
  443.        guchar     *here, 
  444.        guchar     *dest, 
  445.        void       *tmp)
  446. {
  447.   gint    value_chs = 0;
  448.   gint    alpha = 0;
  449.   gint    ch;
  450.  
  451.   switch (dtype)
  452.     {
  453.     case GIMP_RGB_IMAGE:
  454.       value_chs = 3;
  455.       break;
  456.     case GIMP_RGBA_IMAGE:
  457.       value_chs = 3;
  458.       alpha = 3;
  459.       break;
  460.     case GIMP_GRAY_IMAGE:
  461.       value_chs = 1;
  462.       break;
  463.     case GIMP_GRAYA_IMAGE:
  464.       value_chs = 1;
  465.       alpha = 1;
  466.       break;
  467.     default:
  468.       break;
  469.     }
  470.   for (ch = 0; ch < value_chs; ch++)
  471.     {
  472.       if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
  473.     *dest++ = (CH)(vpvals.propagating_rate * best[ch]
  474.                + (1.0 - vpvals.propagating_rate) * here[ch]);
  475.       else
  476.     *dest++ = here[ch];
  477.     }
  478.   if (alpha)
  479.     {
  480.       if (vpvals.propagating_channel & PROPAGATING_ALPHA) /* alpha channel */
  481.     *dest++ = (CH)(vpvals.propagating_rate * best[alpha]
  482.                + (1.0 - vpvals.propagating_rate) * here[alpha]);
  483.       else
  484.     *dest++ = here[alpha];
  485.     }
  486. }
  487.  
  488. static int
  489. value_difference_check (CH  *pos1, 
  490.             CH  *pos2, 
  491.             gint ch)
  492. {
  493.   gint    index;
  494.   int    diff;
  495.  
  496.   for (index = 0 ; index < ch; index++)
  497.     if (channel_mask[index] != 0)
  498.       {
  499.     diff = abs(pos1[index] - pos2[index]);
  500.     if (! ((vpvals.lower_limit <= diff) && (diff <= vpvals.upper_limit)))
  501.       return 0;
  502.       }
  503.   return 1;
  504. }
  505.  
  506. /* mothods for each mode */
  507. static void
  508. initialize_white (GimpImageBaseType   dtype, 
  509.           gint         bytes, 
  510.           CH          *best, 
  511.           CH          *here, 
  512.           void       **tmp)
  513. {
  514.   if (*tmp == NULL)
  515.     *tmp = (void *) g_new (gfloat, 1);
  516.   *(float *)*tmp = sqrt (channel_mask[0] * here[0] * here[0] 
  517.              + channel_mask[1] * here[1] * here[1] 
  518.              + channel_mask[2] * here[2] * here[2]);
  519. }
  520.  
  521. static void
  522. propagate_white (GimpImageBaseType  dtype, 
  523.          gint        bytes, 
  524.          CH         *orig, 
  525.          CH         *here, 
  526.          CH         *best, 
  527.          void       *tmp)
  528. {
  529.   float    v_here;
  530.  
  531.   switch (dtype)
  532.     {
  533.     case GIMP_RGB_IMAGE:
  534.     case GIMP_RGBA_IMAGE:
  535.       v_here = sqrt (channel_mask[0] * here[0] * here[0] 
  536.              + channel_mask[1] * here[1] * here[1] 
  537.              + channel_mask[2] * here[2] * here[2]);
  538.      if (*(float *)tmp < v_here && value_difference_check(orig, here, 3))
  539.     {
  540.       *(float *)tmp = v_here;
  541.       memcpy(best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
  542.     }
  543.       break;
  544.     case GIMP_GRAYA_IMAGE:
  545.     case GIMP_GRAY_IMAGE:
  546.       if (*best < *here && value_difference_check(orig, here, 1))
  547.     *best = *here;
  548.       break;
  549.     default:
  550.       break;
  551.     }
  552. }
  553.  
  554. static void
  555. initialize_black (GimpImageBaseType   dtype, 
  556.           gint         channels, 
  557.           CH          *best, 
  558.           CH          *here, 
  559.           void       **tmp)
  560. {
  561.   if (*tmp == NULL)
  562.     *tmp = (void *) g_new (gfloat, 1);
  563.   *(float *)*tmp = sqrt (channel_mask[0] * here[0] * here[0] 
  564.              + channel_mask[1] * here[1] * here[1] 
  565.              + channel_mask[2] * here[2] * here[2]);
  566. }
  567.  
  568. static void
  569. propagate_black (GimpImageBaseType  image_type, 
  570.          gint        channels, 
  571.          CH         *orig, 
  572.          CH         *here, 
  573.          CH         *best, 
  574.          void       *tmp)
  575. {
  576.   float    v_here;
  577.  
  578.   switch (image_type)
  579.     {
  580.     case GIMP_RGB_IMAGE:
  581.     case GIMP_RGBA_IMAGE:
  582.       v_here = sqrt (channel_mask[0] * here[0] * here[0] 
  583.              + channel_mask[1] * here[1] * here[1] 
  584.              + channel_mask[2] * here[2] * here[2]);
  585.       if (v_here < *(float *)tmp && value_difference_check(orig, here, 3))
  586.     {    
  587.       *(float *)tmp = v_here;
  588.       memcpy (best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
  589.     }
  590.       break;
  591.     case GIMP_GRAYA_IMAGE:
  592.     case GIMP_GRAY_IMAGE:
  593.       if (*here < *best && value_difference_check(orig, here, 1))
  594.     *best = *here;
  595.       break;
  596.     default:
  597.       break;
  598.     }
  599. }
  600.  
  601. typedef struct
  602. {
  603.   gshort min_modified;
  604.   gshort max_modified;
  605.   glong  original_value;
  606.   glong  minv;
  607.   CH     min[3];
  608.   glong  maxv;
  609.   CH     max[3];
  610. } MiddlePacket;
  611.  
  612. static void
  613. initialize_middle (GimpImageBaseType   image_type, 
  614.            gint         channels, 
  615.            CH          *best, 
  616.            CH          *here, 
  617.            void       **tmp)
  618. {
  619.   int index;
  620.   MiddlePacket *data;
  621.  
  622.   if (*tmp == NULL)
  623.     *tmp = (void *) g_new (MiddlePacket, 1);
  624.   data = (MiddlePacket *)*tmp;
  625.   for (index = 0; index < channels; index++)
  626.     data->min[index] = data->max[index] = here[index];
  627.   switch (image_type)
  628.     {
  629.     case GIMP_RGB_IMAGE:
  630.     case GIMP_RGBA_IMAGE:
  631.       data->original_value = sqrt (channel_mask[0] * here[0] * here[0]
  632.                    + channel_mask[1] * here[1] * here[1] 
  633.                    + channel_mask[2] * here[2] * here[2]);
  634.       break;
  635.     case GIMP_GRAYA_IMAGE:
  636.     case GIMP_GRAY_IMAGE:
  637.       data->original_value = *here;
  638.       break;
  639.     default:
  640.       break;
  641.     }
  642.   data->minv = data->maxv = data->original_value;
  643.   data->min_modified = data->max_modified = 0;
  644. }
  645.   
  646. static void
  647. propagate_middle (GimpImageBaseType  image_type, 
  648.           gint        channels, 
  649.           CH         *orig, 
  650.           CH         *here, 
  651.           CH         *best, 
  652.           void       *tmp)
  653. {
  654.   float    v_here;
  655.   MiddlePacket *data;
  656.  
  657.   data = (MiddlePacket *)tmp;
  658.  
  659.   switch (image_type)
  660.     {
  661.     case GIMP_RGB_IMAGE:
  662.     case GIMP_RGBA_IMAGE:
  663.       v_here = sqrt (channel_mask[0] * here[0] * here[0] 
  664.              + channel_mask[1] * here[1] * here[1] 
  665.              + channel_mask[2] * here[2] * here[2]);
  666.       if ((v_here <= data->minv) && value_difference_check(orig, here, 3))
  667.     {    
  668.       data->minv = v_here;
  669.       memcpy (data->min, here, 3*sizeof(CH));
  670.       data->min_modified = 1;
  671.     }
  672.       if (data->maxv <= v_here && value_difference_check(orig, here, 3))
  673.     {    
  674.       data->maxv = v_here;
  675.       memcpy (data->max, here, 3*sizeof(CH));
  676.       data->max_modified = 1;
  677.     }
  678.       break;
  679.     case GIMP_GRAYA_IMAGE:
  680.     case GIMP_GRAY_IMAGE:
  681.       if ((*here <= data->min[0]) && value_difference_check(orig, here, 1))
  682.     {
  683.       data->min[0] = *here;
  684.       data->min_modified = 1;
  685.     }
  686.       if ((data->max[0] <= *here) && value_difference_check(orig, here, 1))
  687.     {
  688.       data->max[0] = *here;
  689.       data->max_modified = 1;
  690.     }
  691.       break;
  692.     default:
  693.       break;
  694.     }
  695. }
  696.  
  697. static void
  698. set_middle_to_peak (GimpImageBaseType  image_type, 
  699.             gint        channels, 
  700.             CH         *here, 
  701.             CH         *best, 
  702.             CH         *dest, 
  703.             void       *tmp)
  704. {
  705.   gint    value_chs = 0;
  706.   gint    alpha = 0;
  707.   gint    ch;
  708.   MiddlePacket    *data;
  709.  
  710.   data = (MiddlePacket *)tmp;
  711.   if (! ((peak_min & (data->minv == data->original_value))
  712.      || (peak_max & (data->maxv == data->original_value))))
  713.     return;
  714.   if ((! peak_includes_equals)
  715.       && ((peak_min & (! data->min_modified))
  716.       || (peak_max & (! data->max_modified))))
  717.       return;
  718.  
  719.   switch (image_type)
  720.     {
  721.     case GIMP_RGB_IMAGE:
  722.       value_chs = 3;
  723.       break;
  724.     case GIMP_RGBA_IMAGE:
  725.       value_chs = 3;
  726.       alpha = 3;
  727.       break;
  728.     case GIMP_GRAY_IMAGE:
  729.       value_chs = 1;
  730.       break;
  731.     case GIMP_GRAYA_IMAGE:
  732.       value_chs = 1;
  733.       alpha = 1;
  734.       break;
  735.     default:
  736.       break;
  737.     }
  738.   for (ch = 0; ch < value_chs; ch++)
  739.     {
  740.       if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
  741.     *dest++ = (CH)(vpvals.propagating_rate * 0.5 * (data->min[ch] + data->max[ch])
  742.                + (1.0 - vpvals.propagating_rate) * here[ch]);
  743.       else
  744.     *dest++ = here[ch];
  745.     }
  746.   if (alpha)
  747.     {
  748.       if (vpvals.propagating_channel & PROPAGATING_ALPHA) /* alpha channel */
  749.     *dest++ = (CH)(vpvals.propagating_rate * best[alpha]
  750.                + (1.0 - vpvals.propagating_rate) * here[alpha]);
  751.       else
  752.     *dest++ = here[alpha];
  753.     }
  754. }
  755.  
  756. static void
  757. set_foreground_to_peak (GimpImageBaseType  image_type, 
  758.             gint        channels, 
  759.             CH         *here, 
  760.             CH         *best, 
  761.             CH         *dest, 
  762.             void       *tmp)
  763. {
  764.   gint    value_chs = 0;
  765.   gint    alpha = 0;
  766.   gint    ch;
  767.   MiddlePacket    *data;
  768.  
  769.   data = (MiddlePacket *)tmp;
  770.   if (! ((peak_min & (data->minv == data->original_value))
  771.      || (peak_max & (data->maxv == data->original_value))))
  772.     return;
  773.   if (peak_includes_equals
  774.       && ((peak_min & (! data->min_modified))
  775.       || (peak_max & (! data->max_modified))))
  776.       return;
  777.  
  778.   switch (image_type)
  779.     {
  780.     case GIMP_RGB_IMAGE:
  781.       value_chs = 3;
  782.       break;
  783.     case GIMP_RGBA_IMAGE:
  784.       value_chs = 3;
  785.       alpha = 3;
  786.       break;
  787.     case GIMP_GRAY_IMAGE:
  788.       value_chs = 1;
  789.       break;
  790.     case GIMP_GRAYA_IMAGE:
  791.       value_chs = 1;
  792.       alpha = 1;
  793.       break;
  794.     default:
  795.       break;
  796.     }
  797.   for (ch = 0; ch < value_chs; ch++)
  798.     {
  799.       if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
  800.     *dest++ = (CH)(vpvals.propagating_rate*fore[ch]
  801.                + (1.0 - vpvals.propagating_rate)*here[ch]);
  802.       else
  803.     *dest++ = here[ch];
  804.     }
  805. }
  806.  
  807. static void
  808. initialize_foreground (GimpImageBaseType   image_type, 
  809.                gint         channels, 
  810.                CH          *here, 
  811.                CH          *best, 
  812.                void       **tmp)
  813. {
  814.   CH *ch;
  815.  
  816.   if (*tmp == NULL)
  817.     {
  818.       *tmp = (void *) g_new (CH, 3);
  819.       ch = (CH *)*tmp;
  820.       gimp_palette_get_foreground (&ch[0], &ch[1], &ch[2]);
  821.     }
  822. }
  823.  
  824. static void
  825. initialize_background (GimpImageBaseType   image_type, 
  826.                gint         channels, 
  827.                CH          *here, 
  828.                CH          *best, 
  829.                void       **tmp)
  830. {
  831.   CH *ch;
  832.  
  833.   if (*tmp == NULL)
  834.     {
  835.       *tmp = (void *) g_new (CH, 3);
  836.       ch = (CH *)*tmp;
  837.       gimp_palette_get_background (&ch[0], &ch[1], &ch[2]);
  838.     }
  839. }
  840.  
  841. static void
  842. propagate_a_color (GimpImageBaseType  image_type, 
  843.            gint        channels, 
  844.            CH         *orig, 
  845.            CH         *here, 
  846.            CH         *best, 
  847.            void       *tmp)
  848. {
  849.   CH *fg = (CH *)tmp;
  850.  
  851.   switch (image_type)
  852.     {
  853.     case GIMP_RGB_IMAGE:
  854.     case GIMP_RGBA_IMAGE:
  855.       if (here[0] == fg[0] && here[1] == fg[1] && here[2] == fg[2] &&
  856.       value_difference_check(orig, here, 3))
  857.     {
  858.       memcpy (best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
  859.     }
  860.       break;
  861.     case GIMP_GRAYA_IMAGE:
  862.     case GIMP_GRAY_IMAGE:
  863.       break;
  864.     default:
  865.       break;
  866.     }
  867. }
  868.  
  869. static void
  870. propagate_opaque (GimpImageBaseType  image_type, 
  871.           gint        channels, 
  872.           CH         *orig, 
  873.           CH         *here, 
  874.           CH         *best, 
  875.           void       *tmp)
  876. {
  877.   switch (image_type)
  878.     {
  879.     case GIMP_RGBA_IMAGE:
  880.       if (best[3] < here[3] && value_difference_check(orig, here, 3))
  881.     memcpy(best, here, channels * sizeof(CH));
  882.       break;
  883.     case GIMP_GRAYA_IMAGE:
  884.       if (best[1] < here[1] && value_difference_check(orig, here, 1))
  885.     memcpy(best, here, channels * sizeof(CH));
  886.       break;
  887.     default:
  888.       break;
  889.     }
  890. }
  891.  
  892. static void
  893. propagate_transparent (GimpImageBaseType  image_type, 
  894.                gint        channels, 
  895.                CH         *orig, 
  896.                CH         *here, 
  897.                CH         *best, 
  898.                void       *tmp)
  899. {
  900.   switch (image_type)
  901.     {
  902.     case GIMP_RGBA_IMAGE:
  903.       if (here[3] < best[3] && value_difference_check(orig, here, 3))
  904.     memcpy(best, here, channels * sizeof(CH));
  905.       break;
  906.     case GIMP_GRAYA_IMAGE:
  907.       if (here[1] < best[1] && value_difference_check(orig, here, 1))
  908.     memcpy(best, here, channels * sizeof(CH));
  909.       break;
  910.     default:
  911.       break;
  912.     }
  913. }
  914.  
  915. /* dialog stuff */
  916.  
  917. static int
  918. vpropagate_dialog (GimpImageBaseType image_type)
  919. {
  920.   GtkWidget *dlg;
  921.   GtkWidget *hbox;
  922.   GtkWidget *frame;
  923.   GtkWidget *table;
  924.   GtkWidget *toggle_vbox;
  925.   GtkWidget *button;
  926.   GtkWidget *sep;
  927.   GtkObject *adj;
  928.   GSList *group = NULL;
  929.   gint      index = 0;
  930.  
  931.   gimp_ui_init ("vpropagate", FALSE);
  932.  
  933.   dlg = gimp_dialog_new (_("Value Propagate"), "vpropagate",
  934.              gimp_standard_help_func, "filters/vpropagate.html",
  935.              GTK_WIN_POS_MOUSE,
  936.              FALSE, TRUE, FALSE,
  937.              _("OK"), vpropagate_ok_callback,
  938.              NULL, NULL, NULL, TRUE, FALSE,
  939.              _("Cancel"), gtk_widget_destroy,
  940.              NULL, 1, NULL, FALSE, TRUE,
  941.              NULL);
  942.  
  943.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  944.               GTK_SIGNAL_FUNC (gtk_main_quit),
  945.               NULL);
  946.  
  947.   hbox = gtk_hbox_new (FALSE, 4);
  948.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
  949.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox, FALSE, FALSE, 0);
  950.   gtk_widget_show (hbox);
  951.  
  952.   /* Propagate Mode */
  953.   frame = gtk_frame_new (_("Propagate Mode"));
  954.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  955.  
  956.   toggle_vbox = gtk_vbox_new (FALSE, 1);
  957.   gtk_container_set_border_width (GTK_CONTAINER (toggle_vbox), 2);
  958.   gtk_container_add (GTK_CONTAINER (frame), toggle_vbox);
  959.     
  960.   for (index = 0; index < num_mode; index++)
  961.     {
  962.       button = gtk_radio_button_new_with_label (group,
  963.                         gettext (modes[index].name));
  964.       group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  965.       gtk_box_pack_start (GTK_BOX (toggle_vbox), button, FALSE, FALSE, 0);
  966.       gtk_object_set_user_data (GTK_OBJECT (button), GINT_TO_POINTER (index));
  967.       gtk_signal_connect (GTK_OBJECT (button), "toggled",
  968.               GTK_SIGNAL_FUNC (gimp_radio_button_update),
  969.               &vpvals.propagate_mode);
  970.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  971.                     index == vpvals.propagate_mode);
  972.       gtk_widget_show (button);
  973.     }
  974.  
  975.   gtk_widget_show (toggle_vbox);
  976.   gtk_widget_show (frame);
  977.  
  978.   /* Parameter settings */
  979.   frame = gtk_frame_new (_("Parameter Settings"));
  980.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  981.  
  982.   table = gtk_table_new (10, 3, FALSE); /* 4 raw, 2 columns(name and value) */
  983.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  984.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  985.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  986.   gtk_container_add (GTK_CONTAINER (frame), table);
  987.  
  988.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  989.                   _("Lower Threshold:"), SCALE_WIDTH, 0,
  990.                   vpvals.lower_limit, 0, 255, 1, 8, 0,
  991.                   TRUE, 0, 0,
  992.                   NULL, NULL);
  993.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  994.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  995.               &vpvals.lower_limit);
  996.  
  997.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  998.                   _("Upper Threshold:"), SCALE_WIDTH, 0,
  999.                   vpvals.upper_limit, 0, 255, 1, 8, 0,
  1000.                   TRUE, 0, 0,
  1001.                   NULL, NULL);
  1002.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1003.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1004.               &vpvals.upper_limit);
  1005.  
  1006.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  1007.                   _("Propagating Rate:"), SCALE_WIDTH, 0,
  1008.                   vpvals.propagating_rate, 0, 1, 0.01, 0.1, 2,
  1009.                   TRUE, 0, 0,
  1010.                   NULL, NULL);
  1011.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1012.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  1013.               &vpvals.propagating_rate);
  1014.  
  1015.   sep = gtk_hseparator_new ();
  1016.   gtk_table_attach (GTK_TABLE (table), sep, 0, 3, 3, 4, GTK_FILL, 0, 0, 0);
  1017.   gtk_widget_show (sep);
  1018.  
  1019.   gtk_table_add_toggle (table, _("To Left"), 0, 1, 5,
  1020.             GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1021.             &direction_mask_vec[Right2Left]);
  1022.   gtk_table_add_toggle (table, _("To Right"), 2, 3, 5,
  1023.             GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1024.             &direction_mask_vec[Left2Right]);
  1025.   gtk_table_add_toggle (table, _("To Top"), 1, 2, 4,
  1026.             GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1027.             &direction_mask_vec[Bottom2Top]);
  1028.   gtk_table_add_toggle (table, _("To Bottom"), 1, 2, 6,
  1029.             GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1030.             &direction_mask_vec[Top2Bottom]);
  1031.   if ((image_type == GIMP_RGBA_IMAGE) | (image_type == GIMP_GRAYA_IMAGE))
  1032.     {
  1033.       sep = gtk_hseparator_new ();
  1034.       gtk_table_attach (GTK_TABLE (table), sep, 0, 3, 7, 8, GTK_FILL, 0, 0, 0);
  1035.       gtk_widget_show (sep);
  1036.  
  1037.       {
  1038.     GtkWidget *toggle;
  1039.     
  1040.     toggle =
  1041.       gtk_table_add_toggle (table, _("Propagating Alpha Channel"),
  1042.                 0, 3, 8,
  1043.                 (GtkSignalFunc) gimp_toggle_button_update,
  1044.                 &propagate_alpha);
  1045.     if (gimp_layer_get_preserve_transparency (drawable_id))
  1046.       {
  1047.         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), 0);
  1048.         gtk_widget_set_sensitive (toggle, FALSE);
  1049.       }
  1050.       }
  1051.       gtk_table_add_toggle (table, _("Propagating Value Channel"), 0, 3, 9,
  1052.                 (GtkSignalFunc) gimp_toggle_button_update,
  1053.                 &propagate_value);
  1054.     }
  1055.   gtk_widget_show (table);
  1056.   gtk_widget_show (frame);
  1057.   gtk_widget_show (hbox);
  1058.   gtk_widget_show (dlg);
  1059.   
  1060.   gtk_main ();
  1061.   gdk_flush ();
  1062.  
  1063.   return vpropagate_interface.run;
  1064. }
  1065.  
  1066. static void
  1067. vpropagate_ok_callback (GtkWidget *widget,
  1068.             gpointer   data)
  1069. {
  1070.   gint i, result;
  1071.  
  1072.   for (i = result = 0; i < 4; i++)
  1073.     result |= (direction_mask_vec[i] ? 1 : 0) << i;
  1074.   vpvals.direction_mask = result;
  1075.  
  1076.   vpvals.propagating_channel = ((propagate_alpha ? PROPAGATING_ALPHA : 0) |
  1077.                 (propagate_value ? PROPAGATING_VALUE : 0));
  1078.  
  1079.   vpropagate_interface.run = TRUE;
  1080.  
  1081.   gtk_widget_destroy (GTK_WIDGET (data));
  1082. }
  1083.  
  1084. static GtkWidget *
  1085. gtk_table_add_toggle (GtkWidget     *table,
  1086.               gchar        *name,
  1087.               gint         x1,
  1088.               gint         x2,
  1089.               gint         y,
  1090.               GtkSignalFunc  update,
  1091.               gint        *value)
  1092. {
  1093.   GtkWidget *toggle;
  1094.   
  1095.   toggle = gtk_check_button_new_with_label(name);
  1096.   gtk_table_attach (GTK_TABLE (table), toggle, x1, x2, y, y+1,
  1097.             GTK_FILL|GTK_EXPAND, 0, 0, 0);
  1098.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  1099.               (GtkSignalFunc) update,
  1100.               value);
  1101.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), *value);
  1102.   gtk_widget_show (toggle);
  1103.  
  1104.   return toggle;
  1105. }
  1106.